package com.castle.fortress.admin.flowable.controller;

import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.castle.fortress.admin.core.annotation.CastleLog;
import com.castle.fortress.admin.core.constants.GlobalConstants;
import com.castle.fortress.admin.flowable.dto.AppAnalyzeDto;
import com.castle.fortress.admin.flowable.dto.FlowableAppAuthDto;
import com.castle.fortress.admin.flowable.dto.FlowableAppDto;
import com.castle.fortress.admin.flowable.entity.FlowableAppEntity;
import com.castle.fortress.admin.flowable.form.dto.FlowableFormConfigDto;
import com.castle.fortress.admin.flowable.form.service.FlowableFormConfigService;
import com.castle.fortress.admin.flowable.service.FlowableAppAuthService;
import com.castle.fortress.admin.flowable.service.FlowableAppService;
import com.castle.fortress.admin.flowable.service.FlowableTemplateService;
import com.castle.fortress.admin.oa.dto.HolidayTypeDto;
import com.castle.fortress.admin.oa.entity.HolidayTypeEntity;
import com.castle.fortress.admin.oa.service.HolidayTypeService;
import com.castle.fortress.admin.system.entity.SysRole;
import com.castle.fortress.admin.system.entity.SysUser;
import com.castle.fortress.admin.utils.ExcelUtils;
import com.castle.fortress.admin.utils.WebUtil;
import com.castle.fortress.common.entity.DynamicExcelEntity;
import com.castle.fortress.common.entity.RespBody;
import com.castle.fortress.common.enums.OperationTypeEnum;
import com.castle.fortress.common.enums.YesNoEnum;
import com.castle.fortress.common.exception.BizException;
import com.castle.fortress.common.respcode.GlobalRespCode;
import com.castle.fortress.common.utils.ConvertUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 流程应用管理表 控制器
 *
 * @author castle
 * @since 2022-09-26
 */
@Api(tags="流程应用管理表管理控制器")
@Controller
public class FlowableAppController {
    @Autowired
    private FlowableAppService flowableAppService;
    @Autowired
    private FlowableAppAuthService flowableAppAuthService;
    @Autowired
    private FlowableFormConfigService flowableFormConfigService;
    @Autowired
    private FlowableTemplateService flowableTemplateService;
    @Autowired
    private HolidayTypeService holidayTypeService;
    /**
     * 流程应用管理表的分页展示
     * @param flowableAppDto 流程应用管理表实体类
     * @param current 当前页
     * @param size  每页记录数
     * @return
     */
    @CastleLog(operLocation = "流程应用管理表分页展示", operType = OperationTypeEnum.QUERY)
    @ApiOperation("流程应用管理表分页展示")
    @GetMapping("/flowable/flowableApp/page")
    @ResponseBody
    @RequiresPermissions("flowable:flowableApp:pageList")
    public RespBody<IPage<FlowableAppDto>> pageFlowableApp(FlowableAppDto flowableAppDto, @RequestParam(required = false) Integer current, @RequestParam(required = false)Integer size){
        Integer pageIndex= current==null? GlobalConstants.DEFAULT_PAGE_INDEX:current;
        Integer pageSize= size==null? GlobalConstants.DEFAULT_PAGE_SIZE:size;
        Page<FlowableAppDto> page = new Page(pageIndex, pageSize);
        IPage<FlowableAppDto> pages = flowableAppService.pageFlowableApp(page, flowableAppDto);

        return RespBody.data(pages);
    }

    /**
     * 流程应用统计数据分页展示
     * 该接口支持数据权限
     * @param flowableAppDto 流程应用管理表实体类
     * @return
     */
    @CastleLog(operLocation = "流程应用管理表列表展示", operType = OperationTypeEnum.QUERY)
    @ApiOperation("流程应用管理表列表展示")
    @GetMapping("/flowable/flowableApp/analyzePage")
    @ResponseBody
    @RequiresPermissions("flowable:flowableApp:analyzePage")
    public RespBody<IPage<AppAnalyzeDto>> pageAnalyzeFlowableApp(FlowableAppDto flowableAppDto){
        SysUser user = WebUtil.currentUser();
        return RespBody.data(flowableAppService.pageAnalyzeFlowableApp(user,flowableAppDto));
    }

    /**
     * 流程应用统计数据列表展示
     * 该接口支持数据权限
     * @param flowableAppDto 流程应用管理表实体类
     * @return
     */
    @CastleLog(operLocation = "流程应用管理表列表展示", operType = OperationTypeEnum.QUERY)
    @ApiOperation("流程应用管理表列表展示")
    @GetMapping("/flowable/flowableApp/analyze")
    @ResponseBody
//    @RequiresPermissions("flowable:flowableApp:analyze")
    public RespBody<List<AppAnalyzeDto>> listAnalyzeFlowableApp(FlowableAppDto flowableAppDto){
        SysUser user = WebUtil.currentUser();
        return RespBody.data(flowableAppService.listAnalyzeFlowableApp(user,flowableAppDto));
    }

    /**
     * 流程统计详情展示
     * @param flowableAppDto 流程应用管理表实体类
     * @return
     */
    @CastleLog(operLocation = "流程统计详情展示", operType = OperationTypeEnum.QUERY)
    @ApiOperation("流程统计详情展示")
    @GetMapping("/flowable/flowableApp/analyzeInfo")
    @ResponseBody
    @RequiresPermissions("flowable:flowableApp:analyzeInfo")
    public RespBody<AppAnalyzeDto> infoAnalyzeFlowableApp(FlowableAppDto flowableAppDto){
        return RespBody.data(flowableAppService.infoAnalyzeFlowableApp(flowableAppDto));
    }

    /**
     * 流程应用管理表的列表展示
     * @param flowableAppDto 流程应用管理表实体类
     * @return
     */
    @CastleLog(operLocation = "流程应用管理表列表展示", operType = OperationTypeEnum.QUERY)
    @ApiOperation("流程应用管理表列表展示")
    @GetMapping("/flowable/flowableApp/list")
    @ResponseBody
    public RespBody<List<FlowableAppDto>> listFlowableApp(FlowableAppDto flowableAppDto){
        List<FlowableAppDto> list = flowableAppService.listFlowableApp(flowableAppDto);
        return RespBody.data(list);
    }

    /**
     * 流程应用管理表保存
     * @param flowableAppDto 流程应用管理表实体类
     * @return
     */
    @CastleLog(operLocation = "流程应用管理表保存", operType = OperationTypeEnum.INSERT)
    @ApiOperation("流程应用管理表保存")
    @PostMapping("/flowable/flowableApp/save")
    @ResponseBody
    @RequiresPermissions("flowable:flowableApp:save")
    public RespBody<String> saveFlowableApp(@RequestBody FlowableAppDto flowableAppDto){
        if(flowableAppDto == null ){
            throw new BizException(GlobalRespCode.PARAM_MISSED);
        }
        FlowableAppEntity flowableAppEntity = ConvertUtil.transformObj(flowableAppDto,FlowableAppEntity.class);
        if(flowableAppService.save(flowableAppEntity)){
            //异步保存应用可见范围
            flowableAppDto.setId(flowableAppEntity.getId());
            flowableAppAuthService.saveAuthAsync(flowableAppDto);
            return RespBody.data("保存成功");
        }else{
            return RespBody.fail(GlobalRespCode.OPERATE_ERROR);
        }
    }

    /**
     * 流程应用管理表编辑
     * @param flowableAppDto 流程应用管理表实体类
     * @return
     */
    @CastleLog(operLocation = "流程应用管理表编辑", operType = OperationTypeEnum.UPDATE)
    @ApiOperation("流程应用管理表编辑")
    @PostMapping("/flowable/flowableApp/edit")
    @ResponseBody
    @RequiresPermissions("flowable:flowableApp:edit")
    public RespBody<String> updateFlowableApp(@RequestBody FlowableAppDto flowableAppDto){
        if(flowableAppDto == null || flowableAppDto.getId() == null || flowableAppDto.getId().equals(0L)){
            throw new BizException(GlobalRespCode.PARAM_MISSED);
        }
        FlowableAppEntity flowableAppEntity = ConvertUtil.transformObj(flowableAppDto,FlowableAppEntity.class);
        if(flowableAppService.updateById(flowableAppEntity)){
            flowableAppAuthService.saveAuthAsync(flowableAppDto);
            return RespBody.data("保存成功");
        }else{
            return RespBody.fail(GlobalRespCode.OPERATE_ERROR);
        }
    }

    /**
     * 流程应用管理表删除
     * @param id
     * @return
     */
    @CastleLog(operLocation = "流程应用管理表删除", operType = OperationTypeEnum.DELETE)
    @ApiOperation("流程应用管理表删除")
    @PostMapping("/flowable/flowableApp/delete")
    @ResponseBody
    @RequiresPermissions("flowable:flowableApp:delete")
    public RespBody<String> deleteFlowableApp(@RequestParam Long id){
        if(id == null ){
            throw new BizException(GlobalRespCode.PARAM_MISSED);
        }
        FlowableAppEntity appEntity = flowableAppService.getById(id);
        if(flowableAppService.removeById(id)) {
            List<Long> ids = new ArrayList<>();
            ids.add(id);
            flowableAppAuthService.delByAppId(ids);
            if(appEntity!=null&&appEntity.getFlowId()!=null){
                flowableTemplateService.delById(appEntity.getFlowId());
            }
            return RespBody.data("保存成功");
        }else{
            return RespBody.fail(GlobalRespCode.OPERATE_ERROR);
        }
    }


    /**
     * 流程应用管理表批量删除
     * @param ids
     * @return
     */
    @CastleLog(operLocation = "流程应用管理表批量删除", operType = OperationTypeEnum.DELETE)
    @ApiOperation("流程应用管理表批量删除")
    @PostMapping("/flowable/flowableApp/deleteBatch")
    @ResponseBody
    @RequiresPermissions("flowable:flowableApp:deleteBatch")
    public RespBody<String> deleteFlowableAppBatch(@RequestBody List<Long> ids){
        if(ids == null || ids.size()<1){
            throw new BizException(GlobalRespCode.PARAM_MISSED);
        }
        flowableTemplateService.delByAppIds(ids);
        if(flowableAppService.removeByIds(ids)) {
            flowableAppAuthService.delByAppId(ids);
            return RespBody.data("保存成功");
        }else{
            return RespBody.fail(GlobalRespCode.OPERATE_ERROR);
        }
    }

    /**
     * 流程应用管理表详情
     * @param id 流程应用管理表id
     * @return
     */
    @CastleLog(operLocation = "流程应用管理表详情", operType = OperationTypeEnum.QUERY)
    @ApiOperation("流程应用管理表详情")
    @GetMapping("/flowable/flowableApp/info")
    @ResponseBody
    @RequiresPermissions("flowable:flowableApp:info")
    public RespBody<FlowableAppDto> infoFlowableApp(@RequestParam Long id){
        if(id == null){
            throw new BizException(GlobalRespCode.PARAM_MISSED);
        }
        FlowableAppEntity flowableAppEntity = flowableAppService.getById(id);
        FlowableAppDto flowableAppDto = ConvertUtil.transformObj(flowableAppEntity,FlowableAppDto.class);
        //获取应用权限
        FlowableAppAuthDto flowableAppAuthDto = new FlowableAppAuthDto();
        flowableAppAuthDto.setAppId(id);
        List<FlowableAppAuthDto> appAuthDtos = flowableAppAuthService.listFlowableAppAuth(flowableAppAuthDto);
        JSONArray user=new JSONArray();
        JSONArray dept= new JSONArray();
        for(FlowableAppAuthDto authDto:appAuthDtos){
            if("user".equals(authDto.getAuthType())){
                user.put(authDto.getAuthId().toString());
            }else if("dept".equals(authDto.getAuthType())){
                dept.put(authDto.getAuthId().toString());
            }
        }
        JSONObject authJson = new JSONObject();
        authJson.set("user",user);
        authJson.set("dept",dept);
        flowableAppDto.setAuthData(authJson.toString());
        return RespBody.data(flowableAppDto);
    }

	/**
     * 动态表头导出 依据展示的字段导出对应报表
     * @param dynamicExcelEntity
     * @param response
     * @throws Exception
     */
    @CastleLog(operLocation = "流程应用导出", operType = OperationTypeEnum.EXPORT)
	@PostMapping("/flowable/flowableApp/exportDynamic")
	@ApiOperation("动态表头导出，依据展示的字段导出对应报表")
	public void exportDynamic(@RequestBody DynamicExcelEntity<FlowableAppDto> dynamicExcelEntity, HttpServletResponse response) throws Exception {
		List<FlowableAppDto> list = flowableAppService.listFlowableApp(dynamicExcelEntity.getDto());
		//字典、枚举、接口、json常量等转义后的列表数据 根据实际情况初始化该对象，null为list数据直接导出
		List<List<Object>> dataList = null;
		/**
        * 根据实际情况初始化dataList,可参照 com.castle.fortress.admin.system.controller.TmpDemoController类中方法：exportDynamic
        */
		ExcelUtils.exportDynamic(response,dynamicExcelEntity.getFileName()+".xlsx",null,list,dynamicExcelEntity.getHeaderList(),dataList);
	}

    /**
     * app统计数据导出
     * @param dynamicExcelEntity
     * @param response
     * @throws Exception
     */
    @CastleLog(operLocation = "app统计数据导出", operType = OperationTypeEnum.EXPORT)
    @PostMapping("/flowable/flowableApp/exportAnalyzeData")
    @ApiOperation("动态表头导出，依据展示的字段导出对应报表")
    public void exportAnalyzeData(@RequestBody DynamicExcelEntity<FlowableAppDto> dynamicExcelEntity, HttpServletResponse response) throws Exception {
        SysUser user = WebUtil.currentUser();
        List<AppAnalyzeDto> list = flowableAppService.listAnalyzeFlowableApp(user,dynamicExcelEntity.getDto());
        //字典、枚举、接口、json常量等转义后的列表数据 根据实际情况初始化该对象，null为list数据直接导出
        List<List<Object>> dataList = null;
        //根据 流程ID 获取 模板 对应 的 配置信息  判断是否假勤的
        FlowableFormConfigDto configDto = flowableFormConfigService.getByFlowId(dynamicExcelEntity.getDto().getFlowId());
        /**
         * 根据实际情况初始化dataList,可参照 com.castle.fortress.admin.system.controller.TmpDemoController类中方法：exportDynamic
         */
        List<Map<String,String>> headerList=new ArrayList<>();
        Map<String,String> applyUserMap = new HashMap<>();
        applyUserMap.put("name","申请人");
        applyUserMap.put("code","_castle_apply_user_name");
        headerList.add(applyUserMap);
        Map<String,String> applyDateMap = new HashMap<>();
        applyDateMap.put("name","申请时间");
        applyDateMap.put("code","_castle_apply_date");
        headerList.add(applyDateMap);
        Map<String,String> applyStatusMap = new HashMap<>();
        applyStatusMap.put("name","审批状态");
        applyStatusMap.put("code","_castle_approve_status");
        headerList.add(applyStatusMap);
        // 是假勤类型的
        if (YesNoEnum.YES.getCode().equals(configDto.getIsHoliday())){
            Map<String,String> leaveType = new HashMap<>();
            leaveType.put("name","请假类型");
            leaveType.put("code","_castle_leave_type");
            headerList.add(leaveType);

            Map<String,String> startTime = new HashMap<>();
            startTime.put("name","请假开始时间");
            startTime.put("code","_castle_start_time");
            headerList.add(startTime);

            Map<String,String> endTime = new HashMap<>();
            endTime.put("name","请假结束时间");
            endTime.put("code","_castle_end_time");
            headerList.add(endTime);

            Map<String,String> leaveDuration = new HashMap<>();
            leaveDuration.put("name","请假时长");
            leaveDuration.put("code","_castle_leave_duration");
            headerList.add(leaveDuration);

            dynamicExcelEntity.setHeaderList(headerList);

            //字典、枚举、接口、json常量的处理
            Map<String,Map<String,Object>> convertMap = new HashMap<>();
            //接口处理 selectUrl 字段使用 接口（{"urlName":"/system/sysRole/list","code":"id","name":"name"}） 转义
            Map<String,Object> urlTranslateMap=new HashMap<>();
            List<HolidayTypeEntity> typeList = holidayTypeService.list(null);
            for(HolidayTypeEntity t:typeList){
                urlTranslateMap.put(t.getId().toString(),t.getName());
            }
            convertMap.put("_castle_leave_type",urlTranslateMap);
            dataList = ExcelUtils.convertToDataList(list,dynamicExcelEntity.getHeaderList(),convertMap,null);
        }
        dynamicExcelEntity.setHeaderList(headerList);
        dynamicExcelEntity.setFileName("应用统计信息");
        ExcelUtils.exportDynamic(response,dynamicExcelEntity.getFileName()+".xlsx",null,list,dynamicExcelEntity.getHeaderList(),dataList);
    }



}
